package com.harveyspace.aes.social.qq;

import com.harveyspace.aes.core.utils.HttpUtil;
import com.harveyspace.aes.core.utils.JsonUtil;
import com.harveyspace.aes.social.Oauth;
import com.harveyspace.aes.social.SocialConfig;
import com.harveyspace.aes.social.exception.SocialException;
import com.harveyspace.aes.social.pojo.AccessTokenInfo;
import com.harveyspace.aes.social.pojo.SocialiteUserInfo;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;

/**
 * OauthQQ
 *
 * @Author <a href="harveyer@163.com">harvey</a>
 * @date 2018/2/9
 */
public class OauthQQ extends Oauth {
    
	private final String TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
	private final String TOKEN_INFO_URL = "https://graph.qq.com/oauth2.0/me";
	private final String USER_INFO_URL = "https://graph.qq.com/user/get_user_info";

	/**
     * @param socialConfig 配置信息
     */
    public OauthQQ(SocialConfig socialConfig) {
        super(socialConfig);
        AUTH_URL = "https://graph.qq.com/oauth2.0/authorize";
    }
    
	/**
	 * 获取授权url
	 * DOC：http://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token
	 * 
	 * @param state OAuth2.0标准协议建议，利用state参数来防止CSRF攻击
	 * @return String 返回类型
	 */ 
	@Override
    public String getAuthorizeUrl(String state) {
		return super.getAuthorizeUrl(state);
	}

	/**
	 * 获取TokenInfo
	 * 
	 * @param accessToken AccessToken
	 * @return String 返回类型
	 */
	private Map<String, String> getOpenId(String accessToken) throws SocialException {

		Map<String, String> params = new HashMap<>();
		params.put("access_token", accessToken);
		params.put("unionid", "1");

		String result;
        try {
            result = HttpUtil.getString(initParams(TOKEN_INFO_URL, params), 1);
            result = parserResult(result);
        } catch (IOException e) {
            String errorMessage = String.format("通过 accessToken[%s] 获取 openId 异常", accessToken);
            logger.error(errorMessage, e);
            throw new SocialException(errorMessage);
        }

        if (isReturnError(result)) {
            throw new SocialException(result);
        }

		return JsonUtil.toMap(result);
	}
	
	/**
	 * 获取用户信息
	 * DOC：http://wiki.connect.qq.com/get_user_info
	 * 
	 * @param accessToken AccessToken
	 * @param openId 平台标识
	 * @return String 返回类型
	 */
	private QQUserInfo getUserInfo(String accessToken, String openId) throws SocialException {

		Map<String, String> params = new HashMap<>();
		params.put("access_token", accessToken);
		params.put("oauth_consumer_key", socialConfig.getClientId());
		params.put("openid", openId);
		params.put("format", "json");

		String result;
        try {
            result = HttpUtil.getString(initParams(USER_INFO_URL, params), 1);
            result = parserResult(result);
        } catch (IOException e) {
            String errorMessage = String.format("通过 accessToken[%s] 获取用户信息异常", accessToken);
            logger.error(errorMessage, e);
            throw new SocialException(errorMessage);
        }

        if (isReturnError(result)) {
            throw new SocialException(result);
        }

		return JsonUtil.toObject(result, QQUserInfo.class);
	}
	
	/**
     * 获取token 返回的是JSON 解析获取到Token以及OpenId
     * 
     * @param code 使用code换取token
     * @return String 返回类型
     * @throws SocialException 异常信息
     */
    @Override
    public AccessTokenInfo getAccessToken(String code) throws SocialException {

        Map<String, String> params = new HashMap<>();
        params.put("code", code);
        params.put("client_id", socialConfig.getClientId());
        params.put("client_secret", socialConfig.getClientSecret());
        params.put("grant_type", "authorization_code");
        params.put("redirect_uri", socialConfig.getRedirectUri());

        String result;

        try {
            result = HttpUtil.getString(initParams(TOKEN_URL, params), 1);
            result = parserResult(result);
        } catch (IOException e) {

            String errorMessage = String.format("通过 code[%s] 获取 access token异常", code);
            logger.error(errorMessage, e);
            throw new SocialException(errorMessage);
        }

        if (isReturnError(result)) {
            throw new SocialException(result);
        }

        Map<String, String> responseMap = parserUrlParams(result);

        AccessTokenInfo accessTokenInfo = JsonUtil.toObject(JsonUtil.toJsonObject(responseMap), AccessTokenInfo.class);

        Map<String, String> data = getOpenId(accessTokenInfo.getAccessToken());
        accessTokenInfo.setOpenId(data.get("openid"));
        accessTokenInfo.setUnionId(data.get("unionid"));

        return accessTokenInfo;
    }

    @Override
    public SocialiteUserInfo getSocialUserInfo(AccessTokenInfo accessTokenInfo) throws SocialException {

		String accessToken = accessTokenInfo.getAccessToken();
		if (StringUtils.isBlank(accessToken)) {
            throw new SocialException("accessToken is Blank!");
		}

		String openId = accessTokenInfo.getOpenId();
		if (StringUtils.isBlank(openId)) {
            throw new SocialException("openId is Blank!");
		}

        SocialiteUserInfo socialiteUserInfo = new SocialiteUserInfo();
        socialiteUserInfo.setUnionId(accessTokenInfo.getUnionId());
        socialiteUserInfo.setOpenId(accessTokenInfo.getOpenId());

        QQUserInfo info = getUserInfo(accessToken, openId);

        if(null != info) {
            String avatar;
            if (StringUtils.isNotBlank(info.getFigureurl_qq_2())) {
                avatar = info.getFigureurl_qq_2();
            } else if (StringUtils.isNotBlank(info.getFigureurl_2())) {
                avatar = info.getFigureurl_2();
            } else if (StringUtils.isNotBlank(info.getFigureurl_1())) {
                avatar = info.getFigureurl_1();
            } else {
                avatar = info.getFigureurl_qq_1();
            }

            socialiteUserInfo.setAvatar(avatar);
            socialiteUserInfo.setNickName(info.getNickname());
        }
        
        return socialiteUserInfo;
    }

    /**
     * 解析，过滤特殊字符
     *
     * @param result 需要过滤的字符串
     * @return 过滤特殊字符的数据结果
     */
    private String parserResult(String result) {

        String data = null;

        if (null != result) {
            Pattern pattern = Pattern.compile("callback\\((.*)\\)");
            Matcher matcher = pattern.matcher(result);
            if (matcher.find()) {
                data = matcher.group(1).trim();
            } else {
                data = result;
            }
        }

        return data;
    }

    /**
     * 判断是否是错误返回
     *
     * @param result 返回值
     * @return boolean
     */
    private boolean isReturnError(String result) {
        return null == result ||
                result.contains("error");
    }
}
